#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <string.h>
#include <stdlib.h>

xmlDocPtr
getdoc (char *docname) {
	xmlDocPtr doc;
	doc = xmlParseFile(docname);
	
	if (doc == NULL ) {
		fprintf(stderr,"Document not parsed successfully. \n");
		return NULL;
	}

	return doc;
}

xmlXPathObjectPtr
getnodeset (xmlDocPtr doc, xmlChar *xpath){
	
	xmlXPathContextPtr context;
	xmlXPathObjectPtr result;

	context = xmlXPathNewContext(doc);
	if (context == NULL) {
		printf("Error in xmlXPathNewContext\n");
		return NULL;
	}
	result = xmlXPathEvalExpression(xpath, context);
	xmlXPathFreeContext(context);
	if (result == NULL) {
		printf("Error in xmlXPathEvalExpression\n");
		return NULL;
	}
	if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
		xmlXPathFreeObject(result);
                printf("No result\n");
		return NULL;
	}
	return result;
}
int
main(int argc, char **argv) {

	char *docname;
	xmlDocPtr doc;
	//xmlChar *xpath = NULL;
	xmlChar xpath[100];
	xmlNodeSetPtr nodeset;
	xmlXPathObjectPtr result;
	int i;
	xmlChar *reg, *field;
	int size = 0, oldsize = 0, cumul = 0;
	unsigned long long value = 0;
	xmlNode *node;
		
	if (argc < 2) {
		printf("Usage: %s xmlfile register value\n", argv[0]);
		return(0);
	}

		
	docname = argv[1];
	doc = getdoc(docname);
		
	if (argc == 2){
		/* List registers available */
		sprintf((char*)xpath,"//register");
	}
	
	else {
		sprintf((char*)xpath,"//register[@name=\"%s\"]/block",argv[2]);
		
	}
	
	result = getnodeset (doc, xpath);

	if (!result) {
		printf("No result.\n");
		xmlXPathFreeObject (result);
		exit(0);
	}
	
	nodeset = result->nodesetval;
	
	
	if (argc == 2){
	
		for (i=nodeset->nodeNr-1; i >=0; i--) {
		
			reg = xmlGetProp(nodeset->nodeTab[i], (const xmlChar*)"name");
			printf("Found register [%s].\n",reg);
			
		}
	}
	
	else {
	
		reg = xmlGetProp(nodeset->nodeTab[0]->parent, (const xmlChar*)"name");
		
		printf("Found register [%s] with [%d] blocks.\n",reg, nodeset->nodeNr);
		
		if (argc == 4){
			
			value = atoll(argv[3]);
			
			if (value > 0xFFFFFFFFUL){
				printf("Care: Input is greater than 32bits.\n");
				exit(-1);
			}
		
			if (value > 0){
										
				for (i=nodeset->nodeNr-1; i >=0; i--) {
					node = nodeset->nodeTab[i]->xmlChildrenNode;
					//reg = xmlGetProp(node->parent, "name");
					field = xmlNodeListGetString(doc, node, 1);
					//printf("Register [%s]: Has a field called [%s] with size [%d] bits.\n", reg , field, size);
					size = atoi(xmlGetProp(node->parent, (const xmlChar*)"size"));
					cumul += size;
					printf("%10s[%02d:%02d] = [%02d].\n", field, cumul-1 , oldsize , (value & 0xFFFFFFFFUL) & (~(0xFFFFFFFFUL << (size))) );
					value >>= size;				
					oldsize = cumul;
					//xmlFree(reg);
					xmlFree(field);
				}
				
			}
		
		}
			
	}
	
	xmlXPathFreeObject (result);
	
	xmlFreeDoc(doc);
	xmlCleanupParser();
	return (1);
}
